home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
CRS
/
crs49.d81
/
hack2-3.sfx
/
hack.3
Wrap
Text File
|
1990-02-12
|
30KB
|
1,002 lines
.%0200! ;*** FETCH( [ZP1]=╞AR╙OURCE, (ZW1)=╥AM0─EST, .┴┘=╠ENGTH )
.%0201!
╙OME WORKING STORAGE LOCATIONS ARE NECESSARY FOR THIS ROUTINE, SINCE IT IS
DESIGNED TO COPY DATA A PAGE AT A TIME. ╘HE SOURCE (ZP1+1) AND DESTINATION
(ZW1+1) PAGE ADDRESSES ARE SAVED AND LATER RESTORED BECAUSE THIS ROUTINE
ALTERS THEM WHILE COPYING. ╔F THE FAR ADDRESS IS IN EXPANSION MEMORY, THIS
ROUTINE DISPATCHES TO THE ╥┼╒ FETCH/STASH CODE.
.%0202! FETCH╠ENGTH = SYS╫ORK
.%0203! FETCH╙AVE╙OURCE = SYS╫ORK+2
.%0204! FETCH╙AVE─EST = SYS╫ORK+3
.%0205!
.%0206! INTERN╥AM0╞ETCH = *
.%0207! LDX ZP1+2
.%0208! BPL +
.%0209! LDX #$91
.%0210! JMP DO╥EU
╔F THE TRANSFER IS LESS THAN ONE PAGE LONG, IT CAN BE DONE BY CALLING THE
FETCH╨AGE CODE DIRECTLY. ╧THERWISE, THE LONG FETCH CODE HAS TO BE CALLED.
.%0211! + CPY #0
.%0212! BNE FETCH╠ONG
.%0213! TAY
.%0214! BNE FETCH╨AGE
.%0215! RTS
.%0216!
╔F THE (INTERNAL) PAGE TO BE FETCHED IS ON ╥┴═1, THE COMMON CODE ROUTINE IS
CALLED; OTHERWISE, THE COPY IS DONE HERE BY SWITCHING ╥┴═0 INTO CONTEXT. ╫E
CAN COPY BETWEEN ╥┴═0 LOCATIONS WITHOUT SWITCHING CONTEXTS FOR EVERY BYTE.
.%0217! FETCH╨AGE = *
.%0218! CPX #BK╥AM0
.%0219! BEQ +
.%0220! JMP COM├OPY╥AM1╘O╥AM0-COM├ODE╙TART+COM├ODE┬UFFER
.%0221! + STX BK╙ELECT
.%0222! DEY
.%0223! BEQ +
.%0224! - LDA (ZP1),Y
.%0225! STA (ZW1),Y
.%0226! DEY
.%0227! BNE -
.%0228! + LDA (ZP1),Y
.%0229! STA (ZW1),Y
.%0230! LDA #BK╙YS
.%0231! STA BK╙ELECT
.%0232! RTS
.%0233!
╘HIS IS CALLED FOR LONG (>=256 BYTE) (INTERNAL) FETCHES. ╔T CALLS THE
FETCH╨AGE CODE REPEATEDLY, AFTER INCREMENTING THE SOURCE AND DESTINATION PAGE
NUMBERS. ╘HE TRANSFER LENGTH IS DECREMENTED UNTIL IT IS LESS THAN 256 BYTES.
.%0234! FETCH╠ONG = *
.%0235! STA FETCH╠ENGTH
.%0236! STY FETCH╠ENGTH+1
.%0237! LDA ZP1+1
.%0238! STA FETCH╙AVE╙OURCE
.%0239! LDA ZW1+1
.%0240! STA FETCH╙AVE─EST
.%0241! LDA FETCH╠ENGTH+1
.%0242! BEQ FETCH╠ONG┼XIT
.%0243! - LDX ZP1+2
.%0244! LDY #0
.%0245! JSR FETCH╨AGE
.%0246! INC ZP1+1
.%0247! INC ZW1+1
.%0248! DEC FETCH╠ENGTH+1
.%0249! BNE -
.%0250!
.%0251! FETCH╠ONG┼XIT = *
╘HIS FETCHES THE LAST CHUNK OF LESS THAN 256 BYTES AND THEN RESTORES THE ZP1
AND ZW1 PARAMETERS TO WHAT THEY WERE BEFORE THIS ROUTINE WAS CALLED.
.%0252! LDY FETCH╠ENGTH
.%0253! BEQ +
.%0254! LDX ZP1+2
.%0255! JSR FETCH╨AGE
.%0256! + LDA FETCH╙AVE╙OURCE
.%0257! STA ZP1+1
.%0258! LDA FETCH╙AVE─EST
.%0259! STA ZW1+1
.%0260! RTS
.%0261!
.%0262! ;*** STASH( (ZW1)=╥AM0╙OURCE, [ZP1]=╞AR─EST, .┴┘=LENGTH )
.%0263!
╙TASH HAS EXACTLY THE SAME STRUCTURE AS FETCH.
.%0264! STASH╠ENGTH = SYS╫ORK
.%0265! STASH╙AVE╙OURCE = SYS╫ORK+2
.%0266! STASH╙AVE─EST = SYS╫ORK+3
.%0267!
.%0268! INTERN╥AM0╙TASH = *
.%0269! LDX ZP1+2
.%0270! BPL +
.%0271! LDX #$90
.%0272! JMP DO╥EU
.%0273! + CPY #0
.%0274! BNE STASH╠ONG
.%0275! TAY
.%0276! BNE STASH╨AGE
.%0277! RTS
.%0278!
.%0279! STASH╨AGE = *
.%0280! CPX #BK╥AM0
.%0281! BEQ +
.%0282! JMP COM├OPY╥AM0╘O╥AM1-COM├ODE╙TART+COM├ODE┬UFFER
.%0283! + STX BK╙ELECT
.%0284! DEY
.%0285! BEQ +
.%0286! - LDA (ZW1),Y
.%0287! STA (ZP1),Y
.%0288! DEY
.%0289! BNE -
.%0290! + LDA (ZW1),Y
.%0291! STA (ZP1),Y
.%0292! LDA #BK╙YS
.%0293! STA BK╙ELECT
.%0294! RTS
.%0295!
.%0296! STASH╠ONG = *
.%0297! STA STASH╠ENGTH
.%0298! STY STASH╠ENGTH+1
.%0299! LDA ZW1+1
.%0300! STA STASH╙AVE╙OURCE
.%0301! LDA ZP1+1
.%0302! STA STASH╙AVE─EST
.%0303! LDA STASH╠ENGTH+1
.%0304! BEQ STASH╠ONG┼XIT
.%0305! - LDX ZP1+2
.%0306! LDY #0
.%0307! JSR STASH╨AGE
.%0308! INC ZP1+1
.%0309! INC ZW1+1
.%0310! DEC STASH╠ENGTH+1
.%0311! BNE -
.%0312!
.%0313! STASH╠ONG┼XIT = *
.%0314! LDY STASH╠ENGTH
.%0315! BEQ +
.%0316! LDX ZP1+2
.%0317! JSR STASH╨AGE
.%0318! + LDA STASH╙AVE╙OURCE
.%0319! STA ZW1+1
.%0320! LDA STASH╙AVE─EST
.%0321! STA ZP1+1
.%0322! RTS
.%0323!
.%0324! ;*** RAM0 LOAD/STORE(.╪) EXPN MEMORY [ZP1] <- -> (ZW1) FOR .┴┘ BYTES
.%0325!
╘HIS IS THE CODE THAT DOES THE FETCHING AND STASHING FROM/TO EXPANSION
MEMORY. ╘HE ONLY DIFFERENCE BETWEEN A FETCH AND A STASH IS THE ╥┼╒ ├ONTROLLER
COMMAND CODE, SO THAT IS AN INPUT PARAMETER. ╘HE ╥┼╒ ├ONTROLLER REGISTERS ARE
SET UP, THE CLOCK IS SLOWED, THE TRANSFER HAPPENS, AND THEN THE CLOCK SPEED IS
RESTORED. ╘HE BULK TRANSFER IS DONE ENTIRELY BY THE ╥┼╒ ├ONTROLLER.
╔NTERESTINGLY, IT WOULD HAVE BEEN FASTER TO TRANSFER THE INTERNAL MEMORY TO
EXPANSION MEMORY AND THEN FETCH IT BACK AGAIN IN ORDER TO ACHIEVE AN INTERNAL
MEMORY TRANSFER (IF YOU HAVE AN ╥┼╒), BUT ╔ DIDN'T BOTHER WITH THAT.
.%0326! DO╥EU = *
.%0327! STA REU+7
.%0328! STY REU+8
.%0329! LDA ZW1
.%0330! LDY ZW1+1
.%0331! STA REU+2
.%0332! STY REU+3
.%0333! LDA ZP1
.%0334! LDY ZP1+1
.%0335! STA REU+4
.%0336! STY REU+5
.%0337! LDA ZP1+2
.%0338! STA REU+6
.%0339! LDY VIC+$30
.%0340! LDA #0
.%0341! STA VIC+$30
.%0342! STX REU+1
.%0343! STY VIC+$30
.%0344! RTS
.%0345!
.%0346! ;*** SNIFF╥┼╒ - DETERMINE NUMBER OF BANKS OF EXPANSION MEMORY
.%0347!
╘HE WORK LOCATIONS ARE USED TO STORE A STRING TO THE FIRST FOUR ADDRESSES OF
EACH EXPANSION MEMORY BANK AND THEN FETCH THEM BACK AGAIN IN ORDER TO
DETERMINE WHETHER THE BANK EXISTS OR NOT. ┼XPANSION BANK #0 IS ALSO CHECKED
AFTER EACH BANK TO SEE IF A BANK NUMBER WRAP-AROUND OCCURED. ╘HE
"REU╙IZE╠IMIT" WILL FORCE THIS ROUTINE TO STOP SEARCHING AFTER THAT NUMBER OF
BANKS HAVE BEEN SNIFFED. ╘HE MAXIMUM VALUE IS 127, SINCE ONLY BANK NUMBERS
$80 TO $╞┼ ARE AVAILABLE. ┬Y CHANGING THIS VALUE, YOU CAN STOP THIS PACKAGE
FROM USING EXPANSION MEMORY RESERVED BY ANOTHER PROGRAM. ╬OTE THAT THIS
PROGRAM USES EXPANSION BANKS 0 UP TO BUT NOT INCLUDING "REU╙IZE╠IMIT".
.%0348! SNIFF╫ORK1 = SYS╫ORK
.%0349! SNIFF╫ORK2 = SYS╫ORK+4
.%0350! REU╙IZE╠IMIT .BYTE 127
.%0351!
.%0352! SNIFF╥┼╒ = *
╚ERE ╔ SAVE THE DATA IN THE MEMORY "BENEATH" THE ╥┼╒ ├ONTROLLER REGISTERS. ╔F
THERE ISN'T A ╥┼╒ INSTALLED, THIS MEMORY WOULD OTHERWISE BE CORRUPTED BY ╔/╧
ADDRESSES BLEEDING THROUGH TO THE UNDERLYING ╥┴═.
.%0353! LDA #BK╥AM0
.%0354! STA BK╙ELECT
.%0355! LDX #$A
.%0356! - LDA REU,X
.%0357! STA WORK┬UFFER,X
.%0358! DEX
.%0359! BPL -
.%0360! LDA #BK╙YS
.%0361! STA BK╙ELECT
╚ERE ╔ INITIALIZE THE CONFIGURATION ╥┼╒ ├ONTROLLER REGSTERS. ╘HEY ARE SET
ONLY ONCE BY THIS PACKEAGE.
.%0362! LDA #$00
.%0363! STA REU+$9
.%0364! STA REU+$A
.%0365! LDA REU+$0
╘HE THREE-BYTE IDENTIFIER STRING IS COPIED INTO THE SOURCE TAG. ╘HE FOURTH
BYTE WILL BE FILLED IN BY THE BANK NUMBER.
.%0366! LDX #2
.%0367! - LDA EXP╥AM╔D,X
.%0368! STA SNIFF╫ORK1,X
.%0369! DEX
.%0370! BPL -
╔NITIALIZATION CONTINUES.
.%0371! LDA #0
.%0372! STA N┼XP┬ANKS
.%0373! LDA #$00
.%0374! LDX #BK┼XP0
.%0375! STA ZP1
.%0376! STA ZP1+1
.%0377! STX ZP1+2
.%0378!
╘HIS IS THE MAIN LOOP. ╔T TESTS THE CURRENT EXPANSION BANK AND THEN GOES ON
TO THE NEXT ONE IF OK. ╧THERWISE, IT STOPS AT THE NUMBER OF OKAY BANKS.
.%0379! - JSR TEST┼XP┬ANK
.%0380! BCS +
.%0381! INC N┼XP┬ANKS
.%0382! INC ZP1+2
.%0383! BNE -
.%0384! + LDA N┼XP┬ANKS
.%0385! BNE +
╥ESTORE THE UNDERLYING ╥┴═ CONTENTS AND EXIT.
.%0386! LDA #BK╥AM0
.%0387! STA BK╙ELECT
.%0388! LDX #$A
.%0389! - LDA WORK┬UFFER,X
.%0390! STA REU,X
.%0391! DEX
.%0392! BPL -
.%0393! LDA #BK╙YS
.%0394! STA BK╙ELECT
.%0395! + RTS
.%0396!
.%0397! ;*** TEST EXPANSION BANK( [ZP1]=┬ANK╨TR ) : .├├=OK
.%0398!
╞IRST CHECKS THAT THE MAXIMUM NUMBER OF ALLOWED EXPANSION BANKS HAS NOT BEEN
EXCEEDED. ╙TORES THE TEST STRING THROUGH THE BANK POINTER AND THEN TESTS TO
SEE THAT THE STRING HAS BEEN STORED CORRECTLY AND THAT THE STRING ON EXPANSION
BANK 0 IS STILL OK (IT WOULDN'T BE OK IF A WRAP-AROUND OCCURED).
.%0399! TEST┼XP┬ANK = *
.%0400! LDA N┼XP┬ANKS
.%0401! CMP REU╙IZE╠IMIT
.%0402! BCC +
.%0403! RTS
.%0404! + LDA ZP1+2
.%0405! STA SNIFF╫ORK1+3
.%0406! LDX #SNIFF╫ORK1
.%0407! LDY #4
.%0408! JSR ZPSTORE
.%0409! JSR TEST┼XP┬ANK╔NTERNAL ;TEST CURRENT BANK
.%0410! BCS +
.%0411! LDA ZP1+2
.%0412! PHA
.%0413! LDA #BK┼XP0
.%0414! STA ZP1+2
.%0415! STA SNIFF╫ORK1+3
.%0416! JSR TEST┼XP┬ANK╔NTERNAL ;TEST EXPANSION BANK 0
.%0417! PLA
.%0418! STA ZP1+2
.%0419! + RTS
.%0420!
╘HIS ROUTINE READS THE BYTES AT ADDRESS [ZP1] AND MAKES SURE THEY ARE THE SAME
AS THE PREVIOUS ROUTINE PUT THERE. ╧N RETURN, THE CARRY FLAG IS SET IF THE
STRING FOUND IS NOT THE SAME AS WHAT WAS PREVIOUSLY PUT OUT.
.%0421! TEST┼XP┬ANK╔NTERNAL = *
.%0422! LDA #$00
.%0423! STA SNIFF╫ORK2
.%0424! STA SNIFF╫ORK2+3
.%0425! LDX #SNIFF╫ORK2
.%0426! LDY #4
.%0427! JSR ZPLOAD
.%0428! LDX #3
.%0429! - LDA SNIFF╫ORK2,X
.%0430! CMP SNIFF╫ORK1,X
.%0431! BNE +
.%0432! DEX
.%0433! BPL -
.%0434! CLC
.%0435! RTS
.%0436! + SEC
.%0437! RTS
.%0438!
╘HIS IS THE THREE-BYTE STRING PUT INTO THE EXPANSION BANKS. ╘HE VALUE MEANS
"╥┴═ IDENTIFIER".
.%0439! EXP╥AM╔D .BYTE "R"
.%0440! .BYTE "╔"
.%0441! .BYTE "D"
.%0442!
.%0443! ;--------------------------------------------------------------------
.%0444! ;*** INITIALIZE DYNAMICALLY ALLOCATED MEMORY() : N┼XP┬ANKS
.%0445!
╘HIS ROUTINE CALLS "FREE" TO INITIALIZE THE FREE MEMORY ON EACH EXISTING
BANK. ╥┴═0 IS SET TO BE FREE FROM $4000 TO THE TOP OF ┬┴╙╔├ MEMORY, SO YOU'LL
HAVE TO CHANGE THE "RAM0╞REE╙TART╨AGE" PARAMETER IF YOU WANT TO HAVE A PROGRAM
THAT OCCUPIES MEMORY HIGHER THAN THIS ADDRESS. ╥┴═1 IS DECLARED TO BE FREE
FROM $0400 TO $╞┼╞╞
.%0446! RAM0╞REE╙TART╨AGE .BYTE $40
.%0447! RAM1╞REE╙TART╨AGE .BYTE $04
.%0448! RAM1╞REE╠ENGTH .BYTE 256-1-$04
.%0449!
.%0450! CURRENT┼XP┬ANK = SYS╫ORK+$F
.%0451!
.%0452! INIT─YNAMIC═EMORY = *
╙ET THE MEMORY ALLOCATION FIRST FREE CHUNK POINTER TO ╬ULL AND SET THE NUMBER
OF BYTES OF FREE MEMORY TO 0.
.%0453! LDX #2
.%0454! - LDA #$00
.%0455! STA FREE═EMORY,X
.%0456! LDA #$FF
.%0457! STA MALLOC╚EAD,X
.%0458! DEX
.%0459! BPL -
─ETERMINE THE LENGTH OF FREE MEMORY ON ╥┴═0 AND FREE THE MEMORY.
.%0460! SEC
.%0461! LDA $1212 ;TOP OF ┬┴╙╔├ PROGRAM ╠OW
.%0462! BEQ +
.%0463! CLC
.%0464! + LDA $1213 ;TOP OF ┬┴╙╔├ PROGRAM ╚IGH
.%0465! SBC RAM0╞REE╙TART╨AGE
.%0466! TAY
.%0467! LDA RAM0╞REE╙TART╨AGE
.%0468! LDX #BK╥AM0
.%0469! JSR INIT╔NTERNAL┬ANK═ALLOC
╞REE THE MEMORY OF ╥┴═1
.%0470! LDA RAM1╞REE╙TART╨AGE
.%0471! LDY RAM1╞REE╠ENGTH
.%0472! LDX #BK╥AM1
.%0473! JSR INIT╔NTERNAL┬ANK═ALLOC
.%0474!
╞OR EACH EXISTING EXPANSION BANK, FREE IT FROM ADDRESSES $0000 TO $╞╞╞7. ┘OU
CANNOT FREE ALL 65536 BYTES SINCE THIS WOULD CAUSE THE LENGTH OF THE FREE
CHUNK TO BE SET TO $0000 WHICH WOULD CAUSE PROBLEMS LATER ON. $╞╞╞8 BYTES ARE
SET TO FREE SINCE THEN LENGTH HAS TO BE A MULTIPLE OF EIGHT BYTES.
.%0475! LDA #0
.%0476! STA CURRENT┼XP┬ANK
.%0477! - LDA CURRENT┼XP┬ANK
.%0478! CMP N┼XP┬ANKS
.%0479! BCS +
.%0480! ORA #BK┼XP0
.%0481! STA ZP1+2
.%0482! LDA #$00
.%0483! STA ZP1
.%0484! STA ZP1+1
.%0485! LDA #$F8
.%0486! LDY #$FF
.%0487! JSR FREE
.%0488! INC CURRENT┼XP┬ANK
.%0489! BNE -
.%0490! + RTS
.%0491!
╘HIS ROUTINE IS CALLED FOR FREEING BANKS ╥┴═0 AND ╥┴═1. ╔T DOES NOTHING OTHER
THAN SET PARAMETERS AND IS PUT IN FOR CONVENIENCE.
.%0492! INIT╔NTERNAL┬ANK═ALLOC = *
.%0493! STA ZP1+1
.%0494! STX ZP1+2
.%0495! LDA #0
.%0496! STA ZP1
.%0497! JMP FREE
.%0498!
.%0499! ;--------------------------------------------------------------------
.%0500! ;*** MALLOC( .┴┘=┬YTES ) : [ZP1]=╞AR╨OINTER
.%0501!
╧NE OF THE BIGGIES. ╘HE "═EM╬EXT╨TR" AND "═EM╠ENGTH" VARIABLES ARE USED TO
STORE THE INFORMATION AT THE START OF THE CURRENT FREE MEMORY CHUNK. "╠ENGTH"
IS USED TO HOLD THE LENGTH INPUT PARAMETER AND "╤" IS THE POINTER TO THE
PREVIOUS FREE MEMORY CHUNK WHEREAS "ZP1" IS USED TO POINT TO THE CURRENT FREE
CHUNK. ╔ PREFIX THESE VARIABLES WITH "MALLOC" TO AVOID NAMING COLLISIONS WITH
OTHER ROUTINES. ╘HE CONCEPT OF LOCAL VARIABLES MIGHT BE A NICE THING FOR
FUTURE ASSEMBLERS TO HAVE.
.%0502! MALLOC═EM╬EXT╨TR = SYS╫ORK
.%0503! MALLOC═EM╠ENGTH = SYS╫ORK+3
.%0504! MALLOC╠ENGTH = SYS╫ORK+5
.%0505! MALLOC╤ = SYS╫ORK+7
.%0506!
.%0507! INTERN┴LLOC = *
┴LIGN THE NUMBER OF BYTES REQUESTED TO AN EVEN MULTIPLE OF EIGHT.
.%0508! CLC
.%0509! ADC #7
.%0510! BCC +
.%0511! INY
.%0512! + AND #$F8
.%0513! STA MALLOC╠ENGTH
.%0514! STY MALLOC╠ENGTH+1
╙ET THE CURRENT FREE CHUNK POINTER TO THE FIRST FREE CHUNK AND SET ╤ TO ╬ULL.
.%0515! LDX #2
.%0516! - LDA MALLOC╚EAD,X
.%0517! STA ZP1,X
.%0518! LDA #$FF
.%0519! STA MALLOC╤,X
.%0520! DEX
.%0521! BPL -
.%0522!
╙EARCH FOR A FREE CHUNK THAT IS LONG ENOUGH TO SATISFY THE REQUEST.
.%0523! MALLOC╠OOK = *
╔F THE CURRENT FREE CHUNK POINTER IS ╬ULL, THEN WE ARE ╙.╧.╠. (╧UT OF ╠UCK)
SINCE THAT MEANS WE HAVE EXHAUSTED THE LIST OF FREE CHUNKS AND HAVE TO REPORT
THAT NO FREE MEMORY COULD BE FOUND.
.%0524! LDA ZP1+2
.%0525! CMP #$FF
.%0526! BNE +
.%0527!
.%0528! MALLOC┼RROR┼XIT = *
.%0529! LDA #$FF ;RETURN A ╬ULL POINTER
.%0530! STA ZP1
.%0531! STA ZP1+1
.%0532! STA ZP1+2
.%0533! LDA #ERR╔NSUFFICIENT═EMORY
.%0534! STA ERRNO
.%0535! SEC
.%0536! RTS
.%0537!
╞ETCH THE HEADER INFORMATION OF THE CURRENT FREE CHUNK AND CHECK THE LENGTH.
╔F THE CURRENT FREE CHUNK IS NOT LARGE ENOUGH, THEN WE SET THE ╤ POINTER TO
THE CURRENT POINTER, AND TAKE THE NEW VALUE FOR THE CURRENT POINTER FROM THE
HEADER OF THE CURRENT FREE CHUNK (MALLOC═EM╬EXT╨TR) AND THEN CONTINUE
SEARCHING.
.%0538! + LDX #MALLOC═EM╬EXT╨TR
.%0539! LDY #5
.%0540! JSR ZPLOAD
.%0541! LDA MALLOC═EM╠ENGTH
.%0542! CMP MALLOC╠ENGTH
.%0543! LDA MALLOC═EM╠ENGTH+1
.%0544! SBC MALLOC╠ENGTH+1
.%0545! BCS MALLOC╟OT┬LOCK
.%0546! LDX #2
.%0547! - LDA ZP1,X
.%0548! STA MALLOC╤,X
.%0549! LDA MALLOC═EM╬EXT╨TR,X
.%0550! STA ZP1,X
.%0551! DEX
.%0552! BPL -
.%0553! JMP MALLOC╠OOK
.%0554!
╬OW, WE'VE FOUND A BLOCK THAT IS LARGE ENOUGH.
.%0555! MALLOC╟OT┬LOCK = *
.%0556! SEC
╙UBTRACT THE NUMBER OF BYTES REQUESTED FROM THE TOTAL NUMBER OF BYTES FREE.
.%0557! LDA FREE═EMORY
.%0558! SBC MALLOC╠ENGTH
.%0559! STA FREE═EMORY
.%0560! LDA FREE═EMORY+1
.%0561! SBC MALLOC╠ENGTH+1
.%0562! STA FREE═EMORY+1
.%0563! BCS +
.%0564! DEC FREE═EMORY+2
╔F THE SIZE OF THE CURRENT FREE CHUNK IS EXACTLY THE SAME AS THE NUMBER OF
BYTES REQUESTED, THEN BRANCH AHEAD.
.%0565! + LDA MALLOC═EM╠ENGTH
.%0566! CMP MALLOC╠ENGTH
.%0567! BNE +
.%0568! LDA MALLOC═EM╠ENGTH+1
.%0569! SBC MALLOC╠ENGTH+1
.%0570! BEQ MALLOC╘AKE╫HOLE┬LOCK
╙UBTRACT THE NUMBER OF BYTES REQUESTED FROM THE LENGTH OF THE CURRENT FREE
CHUNK AND THEN WRITE THE UPDATED HEADER BACK TO THE CURRENT FREE CHUNK.
.%0571! + SEC
.%0572! LDA MALLOC═EM╠ENGTH
.%0573! SBC MALLOC╠ENGTH
.%0574! STA MALLOC═EM╠ENGTH
.%0575! LDA MALLOC═EM╠ENGTH+1
.%0576! SBC MALLOC╠ENGTH+1
.%0577! STA MALLOC═EM╠ENGTH+1
.%0578! LDX #MALLOC═EM╬EXT╨TR
.%0579! LDY #5
.%0580! JSR ZPSTORE
┴DD THE LENGTH OF THE FREE CHUNK TO THE POINTER TO THE START OF THE FREE CHUNK
TO DETERMINE THE ADDRESS OF THE MEMORY THAT HAS JUST BEEN ALLOCATED. ╘HEN
EXIT, RETURNING THIS ADDRESS.
.%0581! CLC
.%0582! LDA ZP1
.%0583! ADC MALLOC═EM╠ENGTH
.%0584! STA ZP1
.%0585! LDA ZP1+1
.%0586! ADC MALLOC═EM╠ENGTH+1
.%0587! STA ZP1+1
.%0588! CLC
.%0589! RTS
.%0590!
╚ERE, THE SIZE OF THE FREE CHUNK IS EXACTLY THE SAME SIZE AS THE REQUEST, SO
THE ENTIRE BLOCK HAS TO BE ALLOCATED AND THUS REMOVED FROM THE FREE CHUNK
LIST. ╘HIS IS WHY THE ╤ POINTER HAS BEEN MAINTAINED.
.%0591! MALLOC╘AKE╫HOLE┬LOCK = *
╔F THERE IS NO PREVIOUS BLOCK (╤ == ╬ULL) THEN SET THE FREE CHUNK LIST HEAD
POINTER TO THE NEXT FREE CHUNK AFTER THE CURRENT ONE. ╘HEN EXIT WITH THE
CURRENT CHUNK AS THE RETURN POINTER.
.%0592! LDA MALLOC╤+2
.%0593! CMP #BK╬ULL
.%0594! BNE +
.%0595! LDX #2
.%0596! - LDA MALLOC═EM╬EXT╨TR,X
.%0597! STA MALLOC╚EAD,X
.%0598! DEX
.%0599! BPL -
.%0600! CLC
.%0601! RTS
╔F THERE IS AN ACTUAL PREVIOUS CHUNK, THEN WE HAVE TO SET IT TO POINT TO THE
NEXT CHUNK FROM THE CURRENT CHUNK. ╘HIS WILL UNLINK THE CURRENT FREE CHUNK
FROM THE FREE CHUNK LIST, THEREBY ALLOCATING IT.
╞IRST, WE SWAP THE ╤ AND CURRENT POINTERS, SINCE WE CAN ONLY ACCESS MEMORY
THROUGH THE "ZP1" POINTER.
.%0602! + LDX #2
.%0603! - LDA ZP1,X
.%0604! LDY MALLOC╤,X
.%0605! STA MALLOC╤,X
.%0606! STY ZP1,X
.%0607! DEX
.%0608! BPL -
╘HEN WE SET THE THE ╬EXT╨OINTER OF THE PREVIOUS FREE CHUNK TO POINT TO THE
NEXT FREE CHUNK AFTER THE CURRENT CHUNK.
.%0609! LDX #MALLOC═EM╬EXT╨TR
.%0610! LDY #3
.%0611! JSR ZPSTORE
┴ND THEN WE RESTORE THE CURRENT CHUNK POINTER AND RETURN IT TO THE USER.
.%0612! LDX #2
.%0613! - LDA MALLOC╤,X
.%0614! STA ZP1,X
.%0615! DEX
.%0616! BPL -
.%0617! CLC
.%0618! RTS
.%0619!
.%0620! ;*** FREE( [ZP1]=╞AR╨OINTER, .┴┘=╠ENGTH ) █ALTERS [ZP1]▌
.%0621!
┴ND HERE IS THE REAL BIGGIE, SINCE ╞REE IS MORE COMPLICATED THAN ═ALLOC. ╘HE
VARIABLES ARE THE SAME AS FOR FREE, EXCEPT THAT "╬EW╨TR" IS REQUIRED TO
REMEMBER THE INPUT PARAMETER TO NEW CHUNK TO BE FREED.
.%0622! FREE═EM╬EXT╨TR = SYS╫ORK
.%0623! FREE═EM╠ENGTH = SYS╫ORK+3
.%0624! FREE╠ENGTH = SYS╫ORK+5
.%0625! FREE╬EW╨TR = SYS╫ORK+7
.%0626! FREE╤ = SYS╫ORK+10
.%0627!
.%0628! INTERN╞REE = *
┴GAIN, ALIGN THE LENGTH OF THE CHUNK. ╘HE POINTER TO THE START OF THE NEW
CHUNK IS ASSUMED TO BE ALIGNED (SINCE MALLOC ONLY RETURNS ALIGNED CHUNKS). ╔F
THE CHUNK POINTER IS NOT ALIGNED, ALL HELL CAN BREAK LOOSE.
.%0629! CLC
.%0630! ADC #7
.%0631! BCC +
.%0632! INY
.%0633! + AND #$F8
.%0634! STA FREE╠ENGTH
.%0635! STY FREE╠ENGTH+1
╙AVE THE NEW CHUNK INPUT PARAMETER AND SET "ZP1" FOR SEARCHING THE FREE CHUNK
LIST. ┴LSO SET ╤ TO ╬ULL SINCE ╤ WILL BE USED TO REMEMBER THE PREVIOUS BLOCK
TO "ZP1".
.%0636! LDX #2
.%0637! - LDA ZP1,X
.%0638! STA FREE╬EW╨TR,X
.%0639! LDA MALLOC╚EAD,X
.%0640! STA ZP1,X
.%0641! LDA #$FF
.%0642! STA FREE╤,X
.%0643! DEX
.%0644! BPL -
.%0645!
╙EARCH FOR THE TWO FREE CHUNKS WHOSE ADDRESSES STRADDLE THE NEW FREE CHUNK.
.%0646! FREE╙EARCH╠OOP = *
╔F THE CURRENT FREE CHUNK POINTER IS ╬ULL OR IF THE CURRENT FREE CHUNK'S BANK
NUMBER IS LESS THAN THE NEW CHUNK'S BANK NUMBER, THEN WE CAN STOP SEARCHING;
WE HAVE FOUND A FREE CHUNK THAT IS "HIGHER" THAN THE NEW CHUNK, SO ╤ AND ZP1
MUST STRADDLE THE ADDRESS OF THE NEW CHUNK. ╬OTE THAT BY USING A "BCC" ON
LINE 652, EXTERNAL MEMORY FREE CHUNKS WILL BE ALLOCATED FIRST. ╔F ╔ HAD USED
A "BCS" THERE, THE INTERNAL MEMORY STARTING FROM ╥┴═0 WOULD BE ALLOCATED
FIRST.
.%0647! LDA ZP1+2
.%0648! CMP #$FF
.%0649! BEQ FREE├OALESCE╤AND╬EW
.%0650! LDA ZP1+2
.%0651! CMP FREE╬EW╨TR+2
.%0652! BCC FREE├OALESCE╤AND╬EW ;** DETERMINES BANK ORDER
╚ERE WE KNOW THAT THE BANK NUMBER IS NOT "HIGHER", SO IF THE BANK NUMBERS ARE
NOT EQUAL, THEN WE CONTINUE SEARCHING. ╔F THE BANK NUMBERS ARE EQUAL, WE MUST
CHECK THE ADDRESSES WITHIN THE BANK TO SEE IF ZP1 IS HIGHER THAN THE NEW
CHUNK. ╔F SO, WE STOP SEARCHING.
.%0653! BNE +
.%0654! LDA ZP1
.%0655! CMP FREE╬EW╨TR
.%0656! LDA ZP1+1
.%0657! SBC FREE╬EW╨TR+1
.%0658! BCS FREE├OALESCE╤AND╬EW
╚ERE WE CONTINUE SEARCHING. ╫E STICK THE CURRENT FREE CHUNK POINTER INTO ╤
AND GET THE NEXT FREE CHUNK POINTER FROM THE CURRENT CHUNK IN MEMORY. ╘HEN WE
GO BACK TO THE TOP OF THE SEARCH.
.%0659! + LDX #FREE═EM╬EXT╨TR
.%0660! LDY #3
.%0661! JSR ZPLOAD
.%0662! LDX #2
.%0663! - LDA ZP1,X
.%0664! STA FREE╤,X
.%0665! LDA FREE═EM╬EXT╨TR,X
.%0666! STA ZP1,X
.%0667! DEX
.%0668! BPL -
.%0669! BMI FREE╙EARCH╠OOP
.%0670!
╚ERE WE KNOW THAT ╤ AND ZP1 STRADDLE THE NEW CHUNK, AND WE TRY TO COALESCE THE
NEW CHUNK TO THE ╤ CHUNK.
.%0671! FREE├OALESCE╤AND╬EW = *
.%0672! LDX #2
.%0673! - LDA FREE╤,X
.%0674! STA ZP1,X
.%0675! DEX
.%0676! BPL -
╔F THE ╤ POINTER IS ╬ULL, THEN THERE IS NO ╤ CHUNK TO COALESCE WITH, SO THE
FREE CHUNK HEAD POINTER IS SET TO POINT TO THE NEW CHUNK AND THE NEW CHUNK
HEADER IS SET TO THE SIZE OF THE NEW CHUNK. ╘HEN NEXT POINTER FOR THE NEW
CHUNK IS SET TO WHAT WAS PREVIOUSLY THE HEAD POINTER.
.%0677! LDA ZP1+2
.%0678! CMP #$FF
.%0679! BNE +
.%0680! LDX #2
.%0681! - LDA MALLOC╚EAD,X
.%0682! STA FREE═EM╬EXT╨TR,X
.%0683! LDA FREE╬EW╨TR,X
.%0684! STA MALLOC╚EAD,X
.%0685! DEX
.%0686! BPL -
.%0687! LDA FREE╠ENGTH
.%0688! LDY FREE╠ENGTH+1
.%0689! STA FREE═EM╠ENGTH
.%0690! STY FREE═EM╠ENGTH+1
.%0691! JMP FREE├OALESCE╬EW┴ND╨
.%0692!
╚ERE THERE ACTUALLY IS A PREVIOUS (╤) CHUNK, SO ITS HEADER IS FETCHED. ╔F IT
IS NOT ON THE SAME BANK AS THE NEW CHUNK, THEN THE NEW CHUNK CANNOT BE
COALESCED WITH IT. ┴LSO, IF THE ADDRESS OF THE NEW CHUNK DOES NOT EXACTLY
FOLLOW THE ╤ CHUNK, THEN THEY CANNOT BE COALESCED.
.%0693! + LDX #FREE═EM╬EXT╨TR
.%0694! LDY #5
.%0695! JSR ZPLOAD
.%0696! LDA ZP1+2
.%0697! CMP FREE╬EW╨TR+2
.%0698! BNE +
.%0699! CLC
.%0700! LDA ZP1
.%0701! ADC FREE═EM╠ENGTH
.%0702! TAX
.%0703! LDA ZP1+1
.%0704! ADC FREE═EM╠ENGTH+1
.%0705! CMP FREE╬EW╨TR+1
.%0706! BNE +
.%0707! CPX FREE╬EW╨TR
.%0708! BNE +
╚ERE, WE KNOW THAT THE PREVIOUS CHUNK AND THE NEW CHUNK CAN BE COALESCED. ╫E
ADD THE LENGTH OF THE NEW CHUNK TO THE LENGTH OF THE PREVIOUS CHUNK AND CHANGE
THE NEW CHUNK POINTER TO POINT TO THE PREVIOUS CHUNK.
.%0709! CLC
.%0710! LDA FREE═EM╠ENGTH
.%0711! ADC FREE╠ENGTH
.%0712! STA FREE═EM╠ENGTH
.%0713! LDA FREE═EM╠ENGTH+1
.%0714! ADC FREE╠ENGTH+1
.%0715! STA FREE═EM╠ENGTH+1
.%0716! LDX #2
.%0717! - LDA FREE╤,X
.%0718! STA FREE╬EW╨TR,X
.%0719! DEX
.%0720! BPL -
.%0721! BMI FREE├OALESCE╬EW┴ND╨
.%0722!
╚ERE, WE KNOW THAT THE PREVIOUS AND NEW CHUNKS CANNOT BE COALESCED. ╫E CHANGE
THE ACTUAL HEADER OF THE PERVIOUS CHUNK TO POINT TO THE NEW CHUNK AND CHANGE
THE NEW CHUNK HEADER LENGTH TO THE FREE REQUEST LENGTH. ╘HE POINTER TO THE
NEXT CHUNK IS ALREADY IN THE NEW CHUNK HEADER FROM BEFORE. ╬OTE THAT NOW WE
ARE USING "═EM╬EXT╨TR" AND "═EM╠ENGTH" TO CONSTRUCT THE NEW FREE CHUNK
HEADER. ╠INE 729 CAUSED ═R. ┬RUCE SOME PROBLEMS BECAUSE HE FORGOT TO STICK
THE "+1" THERE AFTER EXTRACTING THE CODE FROM ┌ED.
.%0723! + LDX #FREE╬EW╨TR
.%0724! LDY #3
.%0725! JSR ZPSTORE
.%0726! LDA FREE╠ENGTH
.%0727! LDY FREE╠ENGTH+1
.%0728! STA FREE═EM╠ENGTH
.%0729! STY FREE═EM╠ENGTH+1
.%0730!
┴T THIS POINT, WE ARE FINISHED TRYING TO COALESCE THE NEW CHUNK WITH THE
PREVIOUS CHUNK, SO WE WILL ATTEMPT TO COALESCE THE NEW CHUNK WITH THE NEXT
HIGHER ADDRESS FREE CHUNK. ╘HE "═EM╬EXT╨TR" AND "═EM╠ENGTH" VARIABLES HOLD
THE HEADER INFORMATION FOR THE NEW CHUNK (THE "═EM╬EXT╨TR" ALSO POINTS TO THE
NEXT FREE CHUNK), AND "╬EW╨TR" POINTS TO THE NEW CHUNK. ╫E CHECK TO SEE IF
THE NEW CHUNK IMMEDIATELY PRECEEDS THE NEXT CHUNK IN THE SAME WAY AS BEFORE.
╬OTE THAT THE CASE OF A ╬ULL NEXT CHUNK POINTER IS HANDLED HERE IMPLICITLY,
SINCE THE BANK NUMBERS WON'T MATCH.
.%0731! FREE├OALESCE╬EW┴ND╨ = *
.%0732! LDA FREE╬EW╨TR+2
.%0733! CMP FREE═EM╬EXT╨TR+2
.%0734! BNE +
.%0735! CLC
.%0736! LDA FREE╬EW╨TR
.%0737! ADC FREE═EM╠ENGTH
.%0738! TAX
.%0739! LDA FREE╬EW╨TR+1
.%0740! ADC FREE═EM╠ENGTH+1
.%0741! CMP FREE═EM╬EXT╨TR+1
.%0742! BNE +
.%0743! CPX FREE═EM╬EXT╨TR
.%0744! BNE +
.%0745!
╚ERE, WE KNOW THAT THE NEW CHUNK CAN BE COALESCED WITH THE NEXT CHUNK. ╫E
HAVE TO FETCH THE HEADER OF THE NEXT CHUNK TO KNOW THE LENGTH AND THE POINTER
TO THE FREE CHUNK AFTER THE NEXT CHUNK. ╫E THEN ADD THE LENGTH OF THE NEXT
CHUNK TO THE LENGTH OF THE NEW CHUNK AND KEEP THE POINTER TO THE CHUNK AFTER
THE NEXT CHUNK FOR THE NEW CHUNK HEADER. ┼FFECTIVELY, THE NEXT FREE CHUNK IS
UNLINKED (SINCE NOTHING IS LEFT TO POINT TO IT) AND THE NEW CHUNK GROWS TO
SWALLOW IT UP.
.%0746! LDX #2
.%0747! - LDA FREE═EM╬EXT╨TR,X
.%0748! STA ZP1,X
.%0749! DEX
.%0750! BPL -
.%0751! LDA FREE═EM╠ENGTH+1
.%0752! PHA
.%0753! LDA FREE═EM╠ENGTH
.%0754! PHA
.%0755! LDX #FREE═EM╬EXT╨TR
.%0756! LDY #5
.%0757! JSR ZPLOAD
.%0758! CLC
.%0759! PLA
.%0760! ADC FREE═EM╠ENGTH
.%0761! STA FREE═EM╠ENGTH
.%0762! PLA
.%0763! ADC FREE═EM╠ENGTH+1
.%0764! STA FREE═EM╠ENGTH+1
.%0765!
╚ERE, WE WRAP THINGS UP. ╫E HAVE THE HEADER FOR THE NEW FREE CHUNK ALL
PREPARED AND WE HAVE TRIED TO COALESCE THE TWO NEIGHBORING CHUNKS TO THE NEW
CHUNK. ┴LL WE DO NOW IS WRITE THE NEW CHUNK HEADER OUT TO MAIN MEMORY AND
INCREASE THE NUMBER OF BYTES FREE VARIABLE BY THE LENGTH OF THE (ORIGINAL)
FREE REQUEST.
.%0766! + LDX #2
.%0767! - LDA FREE╬EW╨TR,X
.%0768! STA ZP1,X
.%0769! DEX
.%0770! BPL -
.%0771! LDX #FREE═EM╬EXT╨TR
.%0772! LDY #5
.%0773! JSR ZPSTORE
.%0774! CLC
.%0775! LDA FREE═EMORY
.%0776! ADC FREE╠ENGTH
.%0777! STA FREE═EMORY
.%0778! LDA FREE═EMORY+1
.%0779! ADC FREE╠ENGTH+1
.%0780! STA FREE═EMORY+1
.%0781! BCC +
.%0782! INC FREE═EMORY+2
╫E ALWAYS RETURN WITH CARRY CLEARED, SINCE WE DON'T CHECK FOR ANY ERRORS.
.%0783! + CLC
.%0784! RTS
.%0785!
.%0786! ;--------------------------------------------------------------------
.%0787! ;*** SORT - THE APPLICATION: READS FROM FILE #1, WRITES TO FILE #2
.%0788!
╘HIS IS WHERE THE ACTUAL APPLICATION CODE STARTS. ╔F YOU WANT TO WRITE YOUR
OWN PROGRAM THAT USES THE DYNAMIC MEMORY ALLOCATION PACKAGE, THEN YOU CAN
FOLLOW THE STRUCTURE OF THIS APPLICATION.
╫E START OFF BY DECLARING THE STORAGE AREAS FOR THE CURRENT LINE BEING
PROCESSED AND FOR THE LINE BEING COMPARED TO THE CURRENT LINE. ╘HE ADDRESSES
REFLECT THE STRUCTURE OF THE RECORD FOR THE INPUT LINE THAT WAS DISCUSSED
EARLIER. ╘HE SORTING FIELD STARTING COLUMN NUMBER PARAMETER IS CAN BE PUT AT
$8╞╞ SINCE THE INPUT LINE CAN ONLY BE 242 CHARACTERS LONG.
.%0789! SORTBUF = $B00
.%0790! SORTBUFLEN = $B03
.%0791! SORTLINE = $B04
.%0792! CMPBUF = $800
.%0793! CMPBUFLEN = $803
.%0794! CMPLINE = $804
.%0795! SORT├OLUMN = $8FF
.%0796!
╘HESE ARE THE ZERO PAGE LOCATIONS THAT SORT USES.
.%0797! EOFSTAT = $02 ;DEFERRED ╙╘ VARIABLE ($90)
.%0798! SORTHEAD = $03 ;POINTER TO FIRST LINE IN LINE LIST
.%0799! SORT╨ = $06 ;CURRENT LINE FOR LIST SEARCHING
.%0800! SORT╤ = $09 ;PREVIOUS LINE FOR LIST SEARCHING
.%0801! HEADER = $0C ;4 BYTES - HOLDS THE CURRENT LINE RECORD'S HEADER
.%0802!
┴ND THESE ARE THE KERNEL ROUTINES THAT ARE CALLED.
.%0803! KERNEL├HKIN = $FFC6
.%0804! KERNEL├HKOUT = $FFC9
.%0805! KERNEL├LRCHN = $FFCC
.%0806! KERNEL├HRIN = $FFCF
.%0807! KERNEL├HROUT = $FFD2
"ECHO╙TATUS" CAN BE CHANGED TO POINT TO AN ╥╘╙ IF YOU DO NOT WANT SORT TO
PRINT STATUS INFORMATION OUT WHILE IT IS WORKING.
.%0808! ECHO╙TATUS = KERNEL├HROUT
.%0809!
.%0810! ;*** GETLINE( SORTLINE ) : .├╙=EOF
.%0811!
╘HIS ROUTINE READS A NEW LINE IN FROM THE CURRENT INPUT CHANNEL AND PUTS IT
INTO THE PROCESSING BUFFER. ╔T RETURNS WITH CARRY SET IF THERE ARE NO MORE
LINES TO READ OR IF A READ ERROR OCCURS.
.%0812! GETLINE = *
.%0813! LDY #0
╘HE "EOFSTAT" IS CHECKED FIRST TO SEE IF THE PREVIOUS CHARACTER READ BEFORE
THE NEW CALL WAS THE LAST OF THE FILE. ╘HIS OVERCOMES THE KERNEL'S AWKWARD
WAY OF SETTING ┼╧╔ FOR THE LAST CHARACTER RATHER THAN WHEN FOR WHEN YOU GO
BEYOND THE LAST CHARACTER.
.%0814! - BIT EOFSTAT
.%0815! BVS GETLINE┼OF
.%0816! JSR KERNEL├HRIN
.%0817! BCS GETLINE┼OF
.%0818! STA SORTLINE,Y
.%0819! INY
.%0820! LDX $90
.%0821! STX EOFSTAT
╔T EXITS WHEN THE MAXIMUM LINE LENGTH IS EXCEEDED OR WHEN A CARRIAGE RETURN IS
ENCOUNTERED.
.%0822! CPY #242
.%0823! BCS GETLINE┼XIT
.%0824! CMP #13
.%0825! BNE -
.%0826! DEY
.%0827!
┴ TRAILING '\0' IS APPENDED TO THE STRING FOR EASIER PROCESSING LATER, AND THE
LENGTH OF THE INPUT LINE RECORD IS RECORDED. ╘HE LENGTH OF THE ENTIRE RECORD
RATHER THAN THE LENGTH OF JUST THE TEXT IS MORE CONVENIENT TO KNOW WHEN
WORKING WITH THE MEMORY PACKAGE.
.%0828! GETLINE┼XIT = *
.%0829! LDA #0
.%0830! STA SORTLINE,Y
.%0831! CLC
.%0832! TYA
.%0833! ADC #5
.%0834! STA SORTBUFLEN
.%0835! CLC
.%0836! RTS
.%0837!
╧N END OF FILE, WE EXIT WITH CARRY SET. ╔F, HOWEVER, WE HAVE READ CHARACTERS
BEFORE THE ┼╧╞ WAS ENCOUNTERED, THEY ARE RETURNED AS BELONGING TO THE LAST
LINE OF THE FILE. ╘RUE ┼╧╞ WILL BE RETURNED ON THE NEXT CALL.
.%0838! GETLINE┼OF = *
.%0839! LDA #$40
.%0840! STA EOFSTAT
.%0841! CPY #0
.%0842! BNE GETLINE┼XIT
.%0843! SEC
.%0844! RTS
.%0845!
.%0846! ;*** PUTLINE( APPLINE )
.%0847!
╘HIS ROUTINE SIMPLY WRITES OUT THE CURRENT LINE ('\0' TERMINATED) AND WRITES
AN ADDITIONAL CARRIAGE RETURN, SINCE THE GETLINE ROUTINE STRIPS OFF THE ├╥.
.%0848! PUTLINE = *
.%0849! LDY #0
.%0850! - LDA SORTLINE,Y
.%0851! BEQ +
.%0852! JSR KERNEL├HROUT
.%0853! INY
.%0854! BNE -
.%0855! + LDA #13
.%0856! JMP KERNEL├HROUT
.%0857!
.%0858! ;*** FETCHLINE( SORT╨=╠INE╨TR, .┴┘=╥AM0BUF )
.%0859!
╘HIS ROUTINE FETCHES THE LINE AT THE POINTER SORT╨ INTO ╥┴═0 AT THE GIVEN
ADDRESS. ╔T HAS TO ZPLOAD THE LINE HEADER FIRST TO DETERMINE THE RECORD SIZE
TO FETCH.